#include <iostream>

// 1. 什么是自我赋值

// class Widget{
// };
// Widget w;
// w = w;   // 自我赋值：对象赋值给自己

// 2. 为什么需要处理自我赋值？
class Bitmap
{
};

class Widget
{
private:
    Bitmap *pb;

public:
    // 有问题的operator=实现
    Widget &operator=(const Widget &rhs)
    {
        delete pb;                // 删除当前的bitmap
        pb = new Bitmap(*rhs.pb); // 复制rhs的bitmap
        return *this;
    }
    Widget &operator=(const Widget &rhs);
    void swap(Widget &rhs);
};

// 如果发生自我赋值，会导致1.delete pb删除了自己的数据；2尝试复制已经删除的数据；3导致未定义行为

// 3. 处理自我赋值的方法
// 方法1. 证同测试
Widget &Widget::operator=(const Widget &rhs)
{
    if (this == &rhs)
        return *this; // 证同测试

    delete pb;
    pb = new Bitmap(*rhs.pb);
    return *this;
}

// 方法2. 异常安全的版本
Widget &Widget::operator=(const Widget &rhs)
{
    Bitmap *pOrig = pb;       // 记住原始pb
    pb = new Bitmap(*rhs.pb); // 复制rhs的bitmap
    delete pOrig;             // 删除原始bitmap
    return *this;
}

// // 方法3. 复制和交换方式
// void Widget::swap(Widget &rhs)
// { // 交换*this和rhs的数据
//     std::swap(pb, rhs.pb);
// }

Widget &Widget::operator=(const Widget &rhs)
{
    Widget temp(rhs); // 复制构造临时对象
    swap(temp);       // 交换数据
    return *this;     // 临时对象析构时释放原来的数据
}

#include <memory>
// 现代C++建议
class Widget_
{
private:
    std::unique_ptr<Bitmap> pb; // 使用智能指针
public:
    Widget_ &operator=(const Widget_ &rhs)
    {
        if (this != &rhs)
        {
            pb = std::make_unique<Bitmap>(*rhs.pb);
        }
        return *this;
    }

    // 或者使用移动语义
    Widget_ &operator=(Widget_ &&rhs) noexcept
    {
        pb = std::move(rhs.pb);
        return *this;
    }
};